// Copyright (C) Moondance Labs Ltd.
// This file is part of Tanssi.

// Tanssi is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Tanssi is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Tanssi.  If not, see <http://www.gnu.org/licenses/>

use {
    crate::{
        tests::common::{
            mock_snowbridge_message_proof,
            xcm::{
                mocknets::{
                    DancelightRelay as Dancelight, DancelightRelayPallet, DancelightSender,
                    SimpleTemplateDancelightPara as DancelightPara,
                },
                *,
            },
        },
        Runtime,
    },
    alloy_sol_types::SolEvent,
    frame_support::assert_ok,
    keyring::AccountKeyring,
    parity_scale_codec::Encode,
    snowbridge_core::{
        inbound::{Log, Message},
        PRIMARY_GOVERNANCE_CHANNEL,
    },
    snowbridge_router_primitives::inbound::envelope::OutboundMessageAccepted,
    sp_core::H256,
    tp_bridge::{
        symbiotic_message_processor::{
            InboundCommand, Message as SymbioticMessage, Payload, MAGIC_BYTES,
        },
        Command,
    },
    xcm_emulator::Chain,
};

#[test]
fn send_msg_to_eth_should_be_process_by_the_bridge() {
    let root_origin = <Dancelight as Chain>::RuntimeOrigin::root();
    let nonce: H256 = sp_core::blake2_256(b"nonce").into();
    let msg_size = 32; // For simplicity since we are hashing the nonce in 32bytes

    // Send message to eth
    Dancelight::execute_with(|| {
        assert_ok!(
            <Dancelight as DancelightRelayPallet>::ExternalValidatorSlashes::root_test_send_msg_to_eth(
                root_origin,
                nonce,
                1,
                msg_size
            )
        );
    });

    // Force process bridge messages
    mocknets::force_process_bridge::<Dancelight, DancelightPara>();

    // xcm command generated by root_test_send_msg_to_eth
    let payload = sp_core::blake2_256((nonce, 0).encode().as_ref()).to_vec();
    let command = Command::Test(payload);

    // msg sent in bridge
    let msgs = mocknets::eth_bridge_sent_msgs();
    let sent_message = msgs.first().unwrap();

    assert_eq!(
        sent_message.channel_id,
        snowbridge_core::PRIMARY_GOVERNANCE_CHANNEL
    );
    assert_eq!(sent_message.command, command.index());
    assert_eq!(sent_message.params, command.abi_encode());
}

#[test]
fn receive_msg_from_eth_validators_are_updated() {
    Dancelight::execute_with(|| {
        let origin =
            <Runtime as frame_system::Config>::RuntimeOrigin::signed(DancelightSender::get());

        // New validators to be added
        let payload_validators = vec![
            AccountKeyring::Alice.to_account_id(),
            AccountKeyring::Charlie.to_account_id(),
            AccountKeyring::Bob.to_account_id(),
        ];

        let payload = Payload {
            magic_bytes: MAGIC_BYTES,
            message: SymbioticMessage::V1(InboundCommand::<Runtime>::ReceiveValidators {
                validators: payload_validators.clone(),
                external_index: 0u64,
            }),
        };

        let event = OutboundMessageAccepted {
            channel_id: <[u8; 32]>::from(PRIMARY_GOVERNANCE_CHANNEL).into(),
            nonce: 1,
            message_id: Default::default(),
            payload: payload.encode(),
        };

        let message = Message {
            event_log: Log {
                // gateway address
                address: <Runtime as snowbridge_pallet_inbound_queue::Config>::GatewayAddress::get(
                ),
                topics: event
                    .encode_topics()
                    .into_iter()
                    .map(|word| H256::from(word.0 .0))
                    .collect(),
                data: event.encode_data(),
            },
            proof: mock_snowbridge_message_proof(),
        };

        // Submit message to the queue
        assert_ok!(
            <Dancelight as DancelightRelayPallet>::EthereumInboundQueue::submit(origin, message)
        );

        let whitelisted =
            <Dancelight as DancelightRelayPallet>::ExternalValidators::whitelisted_validators();

        // Ignore whitelisted
        let new_validators =
            <Dancelight as DancelightRelayPallet>::ExternalValidators::validators()
                .into_iter()
                .filter(|v| !whitelisted.contains(v))
                .collect::<Vec<_>>();

        let expected_validators = payload_validators.clone();

        assert_eq!(new_validators, expected_validators);
    });
}
